package com.seeyon.apps.quartz.abstra;

import com.seeyon.apps.quartz.IQuartzTask;
import com.seeyon.apps.quartz.form.QuartzFormFieldEnum;
import com.seeyon.apps.quartz.vo.condition.JonRunningInfo;
import com.seeyon.cap4.form.api.FormApi4Cap4;
import com.seeyon.cap4.form.bean.*;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.common.exceptions.BusinessException;
import com.seeyon.ctp.util.DateUtil;
import com.seeyon.ctp.util.JDBCAgent;
import com.seeyon.ctp.util.ParamUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 定时任务抽象父类,定时任务必须实现此功能
 * @author fgw
 */
public abstract class AbstractQuartzTask implements IQuartzTask {
	
	protected static final Log log = LogFactory.getLog(AbstractQuartzTask.class);

	/*protected Date lastRunTime;
	protected volatile boolean isRunning = false;*/
	protected String sql;
	protected FormApi4Cap4 formApi4Cap4;
	private ConcurrentHashMap<String, JonRunningInfo> runningInofs = new ConcurrentHashMap<String, JonRunningInfo>();

	
	@Override
	public String executeFunc(Map<String, String> params) {
		String jobName = params.get(JOB_NAME);
		String exeLog;
		String cost;
		String param = params.get(JOB_PARAM);
		if(!canConcurrency(param) && isRunning(jobName)) {
			JonRunningInfo info = runningInofs.get(jobName);
			exeLog = "上次的任务还在运行中，跳过本次执行，最后一次运行时间为：" + DateUtil.format(info.getLastRunTime(), "yyyy-MM-dd HH:mm:ss");
			// 记录日志
			cost =  "0ms";
		} else {
			Long start = System.currentTimeMillis();
			JonRunningInfo info = new JonRunningInfo();
			try {
				runningInofs.put(jobName, info);
				exeLog = taskRun(param);
			} catch (Exception e) {
				log.error(jobName + "任务执行异常：", e);
				exeLog = "任务执行异常：" + e.getMessage();
			} finally {
				// 任务执行完成
				info.setRunning(false);
				runningInofs.put(jobName, info);
			}
			cost = (System.currentTimeMillis() - start) + "ms";
		}
		doLog(jobName, exeLog, cost);
		return exeLog;
	}

	@Override
	public void execute(Map<String, String> params) {
		executeFunc(params);
	}
	
	/**
	 * 记录日志到表单中
	 * 任务名称是唯一标识
	 */
	@Override
	public void doLog(String jobName, String exeLog, String cost) {
		if(null == exeLog || "".equals(exeLog)) {
			exeLog = "没有执行返回结果，请确认代码是否有误!";
		}
		exeLog = exeLog.length() > 3800 ? exeLog.substring(0, 3800) : exeLog;
		// 开始记录日志
		JDBCAgent agent = new JDBCAgent(true, false);
		FormDataMasterBean master = null;
		FormBean logFormBean = null;
		try {
			logFormBean = getLogForm();
		} catch (BusinessException e) {
			log.error("获取表单失败:", e);
			return;
		}
		try {
			String selectSql = getSql();
			List<Object> sqlParam = new ArrayList<Object>();
			sqlParam.add(jobName);
			agent.execute(selectSql, jobName);
			@SuppressWarnings("unchecked")
			List<Map<String, Object>> list = agent.resultSetToList();
			if(null != list && list.size() == 1) {
				Map<String, Object> row = list.get(0);
				Long masterId = ParamUtil.getLong(row, "id");
				master = getFormApi4Cap4().findDataById(masterId, getLogForm(), null);
			} else {
				log.error("获取数据有误：" + selectSql + "，jobName：" + jobName + ", list size : " + list == null ? 0 : list.size());
				return;
			}
		} catch (Exception e) {
			log.error("记录日志失败，请联系定时任务管理模块开发人员", e);
			return;
		} finally {
			agent.close();
		}
		// 处理master  获取子表  只有一个子表  如果有额外需求，自行修改
		Map<String, List<FormDataSubBean>> subTables = master.getSubTables();
		String sonTable = null;
		List<FormDataSubBean> subDatas = null;
		for(String table : subTables.keySet()) {
			sonTable = table;
			subDatas = subTables.get(table);
			break;
		}
		// 只记录最后的10条数据
		List<FormDataSubBean> newSubDatas = new ArrayList<FormDataSubBean>();
		Map<String, Object> row = new HashMap<String, Object>();
		FormTableBean sonTableBean = logFormBean.getSubTableBean().get(0);
		// 开始时间
		FormFieldBean exeTime = sonTableBean.getFieldBeanByDisplay(QuartzFormFieldEnum.exeTime.getDisplay());
		// 日志
		FormFieldBean logField = sonTableBean.getFieldBeanByDisplay(QuartzFormFieldEnum.log.getDisplay());
		// 花费时间
		FormFieldBean costField = sonTableBean.getFieldBeanByDisplay(QuartzFormFieldEnum.costMillis.getDisplay());
		row.put(exeTime.getName(), new Date());
		row.put(logField.getName(), exeLog);
		row.put(costField.getName(), cost);
		FormDataSubBean sub = new FormDataSubBean(row, sonTableBean, master, true);
		newSubDatas.add(sub);
		// 只显示10行 并且是最近一次在最上面
		if(!subDatas.get(0).isEmpty()) {
			// 如果第一行不为空才处理 第一行为空表示只有一行，并且是空的
			int size = subDatas.size() > 19 ? 19 : subDatas.size();
			for(int i = 0; i < size; i++) {
				newSubDatas.add(subDatas.get(i));
			}
		}
		master.setSubData(sonTable, newSubDatas);
		// 保存
		try {
			getFormApi4Cap4().saveOrUpdateFormData(master, logFormBean.getId(), true);
		} catch (Exception e) {
			log.error("保存表单数据失败：", e);
		} 
	}
	
	/**
	 * 任务是否在运行中
	 * @param jobName
	 * @return
	 */
	private boolean isRunning(String jobName) {
		if(null == jobName) {
			return false;
		}
		JonRunningInfo info = runningInofs.get(jobName);
		if(null == info) {
			return false;
		}
		return info.isRunning();
	}

	/**
	 * 默认不能并发
	 */
	@Override
	public boolean canConcurrency(String param) {
		return false;
	}

	public FormApi4Cap4 getFormApi4Cap4() {
		if(null ==formApi4Cap4 ) {
			formApi4Cap4 = (FormApi4Cap4) AppContext.getBean("formApi4Cap4");
		}
		return formApi4Cap4;
	}

	private FormBean getLogForm() throws BusinessException {
		return getFormApi4Cap4().getFormByFormCode(CODE);
	}

	private String getSql() throws BusinessException {
		FormFieldBean field = getLogForm().getFieldBeanByDisplay(QuartzFormFieldEnum.jobBeanName.getDisplay());
		if(null == field) {
			log.error("记录日志失败，请不要修改表单的字段名称:" + QuartzFormFieldEnum.jobBeanName.getDisplay());
			return null;
		}
		if(null == sql) {
			sql = "select id from " + getLogForm().getMasterTableBean().getTableName() + " where " + field.getName() + " = ?";
		}
		return sql;
	}

	/**
	 * 任务参数校验默认返回true，如果有特殊需求，请自行校验
	 */
	@Override
	public String validateParam(String param) {
		return null;
	}
}
